#include <malloc.h>
#include "queue.h"
//#include <utils/Log.h>

/******************************************************************************
  API Function define
 ******************************************************************************/
int q_init(queue_t** q, QueType type, int msize, int delay) 
{
	if (*q){return -1;}
	if( (type >= UNKNOWN_TYPE) ){
		return -1;
	}
	if( (REALTIME_FIRST == type) &&
	     (delay > msize) ){
		 return -1;
	}
	*q = (queue_t*)malloc(sizeof(queue_t));
	if (!(*q)){
		return -1;
	}
	(*q)->head = 
		(node_t*)malloc(sizeof(node_t));
	if (!((*q)->head)) {
	   	 free(*q);
	    	*q = 0;
	    	return -1;
	}
	(*q)->head->last = (*q)->head;
	(*q)->head->next = (*q)->head;
	(*q)->head->data = 0;
	if( (REALTIME_FIRST == type) ){
		(*q)->msize = msize;
		(*q)->delay = delay;
	}else{
		(*q)->msize = 0;
		(*q)->delay = 0;
	}
	(*q)->overflow = 0;
	(*q)->type = type;
	(*q)->size = 0;
	(*q)->pps = NULL;
	(*q)->ppsL = 0;
	(*q)->ppsB = false;
	pthread_mutex_init(&(*q)->mutex, 0);
	pthread_cond_init(&(*q)->condv, 0);
	return 1;
}

int q_push_head(queue_t* q, void* data)
{
    //ALOGD("%s:Enter CallBack ",__func__);
    //ALOGD("%d:push data size CallBack ",q->size);
	node_t* node = NULL;
	node_t* head = NULL;
	void* result = NULL;

	if (!q){return -1;}
	node = (node_t*) malloc(sizeof(node_t));
	if (!node){return -1;}
	node->data = data;
	
	pthread_mutex_lock(&q->mutex);
	if( (REALTIME_FIRST == q->type) ){
	    if( (q->size >= q->msize) ){
			node_t* node1;
			q->overflow = 1;
			q->size--;
			head = q->head;
			node1 = head->last;
			head->last = node1->last;
			node1->last->next = head;
			result = node1->data;
			free(node1);
			free_AVPacket(result);
			//__android_log_print(
			//	ANDROID_LOG_DEBUG,
			//	"overflow", 
			//	"queue[%d]", 
			//	q->size);
	    }
	}
	q->size++;
	head = q->head;
	node->next = head->next;
	head->next->last = node;
	node->last = head;
	head->next = node;
	pthread_cond_signal(&q->condv);
	pthread_mutex_unlock(&q->mutex);
	return 0;
}

void* q_pop_tail(queue_t* q)
{
    //ALOGD("%s:Enter CallBack ",__func__);
    //ALOGD("%d:pop data size CallBack ",q->size);
	node_t* node = NULL;
	node_t* head = NULL;
	void* result = NULL;

	if (!q){return 0;}
	pthread_mutex_lock(&q->mutex);
	while (!q->size) {
		pthread_cond_wait(
			&q->condv, &q->mutex);
	}
	if (q->size > 0){
		if( (1 == q->overflow) ){
			while( (q->size > q->delay) )
			{
				q->size--;
				head = q->head;
				node = head->last;
				head->last = node->last;
				node->last->next = head;
				result = node->data;
				free(node);
				free_AVPacket(result);
			}
			q->overflow = 0;
		}
		q->size--;
		head = q->head;
		node = head->last;
		head->last = node->last;
		node->last->next = head;
		result = node->data;
		free(node);
	}else{
		result = 0;
	}
	pthread_mutex_unlock(&q->mutex);
	return result;
}

int q_size(queue_t* q) {
	int size = 0;
	if (!q){return -1;}
    	pthread_mutex_lock(&q->mutex);
    	size = q->size;
    	pthread_mutex_unlock(&q->mutex);
    	return size;
}

void q_abort(queue_t* q, void (*func)(void*))
{
	node_t* node = NULL;
	void* data = NULL;

	if (!q){return;}
	pthread_mutex_lock(&q->mutex);
	while (q->size > 0) {
		node = q->head->next;
		data = node->data;
		if (data && func)
			func(data);
		q->head->next = node->next;
		free(node);
		q->size--;
	}
	q->head->next = q->head;
	q->head->last = q->head;
	pthread_mutex_unlock(&q->mutex);
}

void q_wake(queue_t* q) {
	if (!q){return;}
	pthread_mutex_lock(&q->mutex);
	if (!q->size)
		q->size = -1;
	pthread_cond_broadcast(&q->condv);
	pthread_mutex_unlock(&q->mutex);
}

void q_free(queue_t** q, void (*func)(void*))
{
	node_t* node = NULL;
	void* data = NULL;

	if (!(*q)){return;}
	q_abort(*q, func);
	pthread_mutex_destroy(&(*q)->mutex);
	pthread_cond_destroy(&(*q)->condv);
	if( (NULL != (*q)->head) ){
		free((*q)->head);
	}
	if( (NULL != (*q)->pps) ){
		free((*q)->pps);
	}
	free(*q);
	*q = 0;
}

void free_AVPacket(void* data) {
    if (data) {
		if( (NULL != ((AVPacket *)data)->data) ){
			free(((AVPacket *)data)->data);
		}
		free(data);
    }
}

